<template>
  <el-form
    :model="value"
    ref="formRef"
    class="pro-form"
    v-loading="loading"
    @submit.prevent="handleSubmit"
  >
    <RowWrapper :grid="grid" v-bind="grid ? rowProps : {}">
      <!--  item内容区   -->
      <FormItems :grid="grid" v-model="value" :columns="columns">
        <template v-for="(_item, name) in itemsSlots" #[name]="slotData" :key="name">
          <slot :name="name" v-bind="slotData" />
        </template>
      </FormItems>
    </RowWrapper>

    <slot></slot>

    <!--  底部  -->
    <slot name="footer" v-bind="{ handleReset, handleSubmit, submitLoading }">
      <el-button @click="handleReset" v-bind="resetButtonProps" v-if="isReset">
        <!-- 重置 -->
        {{ resetText || $t('form.reset') }}
      </el-button>
      <el-button
        type="primary"
        :loading="submitLoading"
        v-bind="submitButtonProps"
        @click="!isKeyPressSubmit && handleSubmit()"
        :native-type="isKeyPressSubmit ? 'submit' : 'button'"
      >
        <!-- 提交 -->
        {{ submitText || $t('form.submit') }}
      </el-button>
    </slot>
  </el-form>
</template>

<script setup>
import { defineModel, computed, useSlots, ref, useTemplateRef, onMounted, nextTick } from 'vue'
import RowWrapper from '../components/row-wrapper.vue'
import FormItems from '../components/form-items.vue'
import { initializeInitValues } from '../utils.js'
import {dataOmit} from '@/utils/util.js'

defineOptions({
  name: 'ProForm',
})

const props = defineProps({
  columns: { type: Array, default: () => [] }, // 表单配置项
  initialValues: { type: Object, default: null }, // 初始值
  params: { type: Object, default: null }, // 额外的固定参数  与 request 配合使用
  request: { type: Function, default: null }, // 表单初始化时，自动发送请求以获取并回填数据，返回值会覆盖给 initialValues

  isFooter: { type: Boolean, default: true }, // 是否显示表单底部
  submitButtonProps: { type: Object, default: null }, // 提交按钮的 props
  resetButtonProps: { type: Object, default: null }, // 重置按钮的 props
  submitText: { type: String, default: null }, // 提交按钮的文本
  resetText: { type: String, default: null }, // 重置的文本
  submitLoading: { type: Boolean, default: false }, // 提交按钮的 loading
  isReset: { type: Boolean, default: true }, // 是否显示重置表单

  isKeyPressSubmit: { type: Boolean, default: false }, // 是否使用回车提交
  autoFocusFirstInput: { type: Boolean, default: false }, // 自动 focus 表单第一个输入框
  grid: { type: Boolean, default: false }, // 开启栅格化模式，宽度默认百分比，请使用 colProps 控制宽度
  rowProps: { type: Object, default: null }, // 开启 grid 模式时传递给 Row
})

const value = defineModel()
const slots = useSlots()
const formRef = useTemplateRef('formRef')
const emit = defineEmits(['submit', 'reset', 'submitError'])
const initValues = initializeInitValues(props.initialValues || {}, value.value) // 初始值 initialValues和request合并使用
const loading = ref(false)

// 表单条目下插槽
const itemsSlots = computed(() => {
  // 排除掉不需要的插槽（当前的组件其他的插槽）
  return dataOmit(['footer', 'default'], slots)
})

const recoverValue = () => {
  // 先清空所有属性
  Object.keys(value.value).forEach((key) => {
    delete value.value[key]
  })
  // 再重新赋值
  Object.assign(value.value, initValues)
}

onMounted(async () => {
  if (initValues && Object.keys(initValues).length) {
    recoverValue()
  }
  // 初始化请求数据
  if (props.request) {
    try {
      loading.value = true
      const data = await props.request(props.params)
      if (data && Object.keys(data).length) {
        // 覆盖出初始值
        Object.assign(initValues, data)
        recoverValue()
      }
    } finally {
      loading.value = false
    }
  }
  // 自动聚焦第一个输入框
  if (props.autoFocusFirstInput) {
    await nextTick()
    focusFirstInput()
  }
})

// 清空校验
const clearValidate = () => {
  formRef.value?.clearValidate()
}

/**
 * 提交表单
 * @returns {Promise<boolean>}
 */
const handleSubmit = async () => {
  try {
    const valid = await formRef.value?.validate()
    if (valid) {
      emit('submit', value.value)
    }
  } catch (errors) {
    emit('submitError', errors)
  }
}

/**
 * 重置表单
 */
const handleReset = () => {
  clearValidate()
  recoverValue()
  emit('reset', value.value)
}

// 聚焦第一个输入框的方法
const focusFirstInput = () => {
  try {
    if (formRef.value?.$el) {
      const formElement = formRef.value.$el
      // 查找第一个可聚焦的输入元素
      const firstInputElement = formElement.querySelector(
        'input:not([disabled]):not([readonly]), textarea:not([disabled]):not([readonly]), select:not([disabled])',
      )
      if (firstInputElement) {
        firstInputElement.focus()
      }
    }
  } catch (e) {
    console.warn('聚焦第一个输入框异常！', e)
  }
}

defineExpose({
  formRef,
  handleSubmit,
  handleReset,
  clearValidate,
  focusFirstInput,
})
</script>

<style scoped lang="scss"></style>
